package MsgSystem;

import Databases.DatabaseDao;
import Databases.DbDAO;
import UserUnit.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.FromContainsFilter;
import org.jivesoftware.smack.filter.NotFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.muc.MultiUserChat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
import org.jivesoftware.smackx.filetransfer.*;

public class ImpInstantMessage implements InstantMessage, Serializable {

    private static final Log LOGGER = LogFactory.getLog("common");
    public static final String GENERIC_MESSAGE = "GENERIC_MESSAGE";
    private PacketListener listenner;
    XMPPConnection connect = null;
    PacketFilter filter = null;
    MultiUserChat chat = null;
    private String username, password, resource;
    boolean received = false;
    String user2;
    Message msg;
    ArrayList contacts;
    ArrayList<ImpPhoto> results;
    ArrayList<ImpPhoto> finalResults;
    TransferRequest rece;
    boolean isLogin;
    String user;
    ReceiveMessages recMsg = null;

    public ImpInstantMessage() {
    }
//Function login connects the user to the server of googletalk. At the same time add a packet listenner to the connection to recieve,
//in the future, the packets of the other users. In this function it has been saved also the list of contacts. 

    public boolean login(String username, String password, String resource) {
        this.user2 = username;
        this.username = username;
        this.password = password;
        this.resource = resource;
        ConnectionConfiguration config = new ConnectionConfiguration("talk.google.com", 5222, "gmail.com");
        config.setSASLAuthenticationEnabled(true);
        config.setReconnectionAllowed(true);
        connect = new XMPPConnection(config);
        try {
            connect.connect();
            connect.login(username, password, resource);
            LOGGER.info("User " + username + " is connected");
            this.connect = connect;
            isLogin = true;
            filter = new AndFilter(new PacketTypeFilter(Message.class), new NotFilter(new FromContainsFilter(connect.getUser())));
            connect.createPacketCollector(filter);
            chat = new MultiUserChat(connect, username);

            listenner = (PacketListener) new ImpListener(this);
            connect.addPacketListener(listenner, filter);

            recMsg = new ReceiveMessages(this);
            final FileTransferManager manager = new FileTransferManager(connect);
            FileTransferNegotiator.setServiceEnabled(connect, true);
            manager.addFileTransferListener(recMsg);


        } catch (Throwable ex) {

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("User " + username + " can't connect to googleTalk");
            } else {
                LOGGER.info("User " + username + " can't connect to googleTalk");
            }
            LOGGER.fatal("SYSTEM ABORT!");
        }

        return isLogin;

    }
//The function logout disconnect the user of the chat.

    public void logout() {
        if (connect != null) {
            connect.disconnect();
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("User " + username + " is disconnected");
            } else {
                LOGGER.info("User " + username + " is disconnected");
            }
        }


    }
//The function sendMessage recieve a GenericMessage packet and a String with its destination and send the packet to this user. 

    public void setReceiveMessage(TransferRequest rece) {
        rece = new TransferRequest();
        this.rece = rece;
    }

    public void setRecBool(Boolean bool) {
        rece.setBoolean(true);
    }

    public TransferRequest receBool() {
        return rece;
    }

    public void sendMessage(String to, ImpGenericMessage igm) {
        msg = new Message();

        msg.setTo(to);
        msg.setPacketID("GENERIC_MESSAGE");
        msg.setProperty("GENERIC_MESSAGE", igm);

        try {

            chat.sendMessage(msg);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Message send to: " + msg.getTo());
            }
        } catch (XMPPException ex) {
            Logger.getLogger(ImpInstantMessage.class.getName()).log(Level.SEVERE, null, ex);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Impossible send the message to:" + msg.getTo());
            } else {
                LOGGER.info("Impossible send the message to:" + msg.getTo());
            }
        }

    }

    //This function explore the users connected and returns a list with this information
    public ArrayList Contacts() {
        contacts = new ArrayList();
        Roster roster = this.getConnection().getRoster();
        for (Iterator<RosterEntry> i = roster.getEntries().iterator(); i.hasNext();) {
            RosterEntry re = (RosterEntry) i.next();
            contacts.add(re.getUser());
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Contacts added to " + username + " list of contacts");
        }
        return contacts;
    }

    public XMPPConnection getConnection() {

        return connect;
    }

    public String getUser() {
        this.user = connect.getUser();
        return user;
    }

    public String getUsername() {
        return user2;
    }

    public void setUser(String user) {
        this.username = user;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void sendAll(ArrayList contacts, ImpGenericMessage igm) {
        Roster roster = connect.getRoster();
        for (Iterator<RosterEntry> i = roster.getEntries().iterator(); i.hasNext();) {
            RosterEntry re = (RosterEntry) i.next();
            igm.setDestination(re.getUser());
            sendMessage(re.getUser(), igm);
        }
    }

    public boolean getBoolean() {
        return received;
    }

    public boolean passResults(ImpSearchResult isr) {

        finalResults = new <ImpPhoto> ArrayList();
        this.finalResults = isr.getSearchResults();
        received = true;
        return received;

    }

    public ArrayList getFinalResults() {
        received = false;
        return finalResults;
    }

    public ArrayList extract(ImpSearchProfile isp) {
        results = new ArrayList();
        DbDAO ins;
        Object[] Parameters;
        Map<String, ImpPhoto> result;
        ImpPhoto pruebaphoto = null;
        List<String> phs = null;
        if (isp.getOntology() != null) {
            String option = isp.getOntology();
            Parameters = new String[]{option};
            if (option.equalsIgnoreCase("animals") || option.equalsIgnoreCase("news")) {
                ins = DatabaseDao.getInstance();
                result = ins.searchBySpecificOntologyFirstLevel(Parameters);
                phs = new ArrayList<String>(result.keySet());
                Collections.sort(phs);
                for (Iterator iterator = phs.iterator(); iterator.hasNext();) {
                    String id = (String) iterator.next();
                    pruebaphoto = result.get(id);
                    pruebaphoto.setThumbnail(pruebaphoto.getUrl());
                    results.add(pruebaphoto);
                }
            } else {
                ins = DatabaseDao.getInstance();
                result = ins.searchBySpecificOntologySecondLevel(Parameters);
                phs = new ArrayList<String>(result.keySet());
                Collections.sort(phs);
                for (Iterator iterator = phs.iterator(); iterator.hasNext();) {
                    String id = (String) iterator.next();
                    pruebaphoto = result.get(id);
                    pruebaphoto.setThumbnail(pruebaphoto.getUrl());
                    results.add(pruebaphoto);
                }
            }
        }
        Parameters = new String[]{isp.getKeyValue()};
        ins = DatabaseDao.getInstance();
        ins.seachBySpecificTag(Parameters);
        result = ins.seachBySpecificTag(Parameters);
        if (result.isEmpty()) {
            if (results.isEmpty()) {
                pruebaphoto = new ImpPhoto();
                pruebaphoto.setName("There are no photos with this tags");
                results.add(pruebaphoto);
            }
        } else {
            phs = new ArrayList<String>(result.keySet());

            Collections.sort(phs);
            for (Iterator iterator = phs.iterator(); iterator.hasNext();) {
                String id = (String) iterator.next();
                pruebaphoto = result.get(id);
                pruebaphoto.setThumbnail(pruebaphoto.getUrl());
                results.add(pruebaphoto);
            }
        }

        return results;
    }
    //This function print the connected users but isn't neccesary for the correct run of the program. It's an extra function.
    /*
     * public void ImprimeContactos (ArrayList contacts){ Iterator
     * it=contacts.iterator(); System.out.println("Your contats are: ");
     * while(it.hasNext()){ System.out.println(it.next()+ "\n"); }
      }
     */
}
